package net.wanderinghorse.jsonmessage;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

/**
 * This extension of the RequestHandler interface exists to assist in creating
 * RequestHandler implementations which require information from a servlet
 * (e.g. for access to the servlet session or HTTP cookies).
 */
public interface RequestHandlerServlet extends RequestHandler {
    /**
     * A container providing limited access to inbound HTTP request/response
     * information. It does not provide the handler with access to the
     * protocol/connection-level details, e.g. reading HTTP headers or setting response
     * codes, but provides access to:
     *
     * - Cookies
     * - Session
     */
    public static class ServletInfo {
        private HttpServletRequest req;
        private HttpServletResponse resp;

        /**
         * Sets the inbound request and response objects, which this object
         * will then provide partial access to.
         * 
         * @param req The inbound request, which may not be null.
         * @param resp The inbound response, which may not be null.
         * @throws IllegalArgumentException If either argument is null.
         */
        public ServletInfo( HttpServletRequest req, HttpServletResponse resp ) {
            if( (null == req) || (null == resp) ) {
                throw new IllegalArgumentException(getClass().getName()+": no arguments to the ctor may be null!");
            }
            this.req = req;
            this.resp = resp;
        }

        /**
         * Adds the given cookie to the underlying HTTP response.
         *
         * @param c The cookie to add.
        */
        public void addCookie( Cookie c ) {
            this.resp.addCookie( c );
        }

        /**
         * Calls c.setMaxAge(0), c.setValue("") and calls addCookie(c). In theory that will
         * cause the cookie to be unset when the response is sent, but this is reportedly
         * browser-dependent.
         *
         * @param c The cookie to remove.
         */
        public void removeCookie( Cookie c ) {
            c.setValue("");
            c.setMaxAge(0);
            addCookie( c );
        }

        /**
         * Returns the cookies associated with the HTTP request.
         * @return The list of cookies, or null if there are none.
         */
        public Cookie[] getCookies() {
            return this.req.getCookies();
        }

        /**
         * Equivalent to getSession(true).
         * @return The HttpSession associated with the request.
         */
        public HttpSession getSession() {
            return this.getSession(true);
        }

        /**
         * Returns the HttpSession. If createIfNotExists is false and no session
         * exists, then null is created, otherwise the session is created
         * if needed.
         *
         * @param createIfNotExists Whether or not to create the session if it doesn't already exist.
         * @return The HttpSession associated with the request, or null if createIfNotExists
         * is false and no session already exists.
         */
        public HttpSession getSession(boolean createIfNotExists) {
            return this.req.getSession( createIfNotExists );
        }

        /**
         * Gets the name of the remote user if he has been "logged in", else null.
         * What "logged in" means is unclear - the Java API docs don't specify, but my assumption
         * is that it refers to HTTP authentication.
         * @return The user's name, or null if no user is "logged in."
         */
        public String getRemoteUser() {
            return req.getRemoteUser();
        }

        /**
         * Returns the "context path", which is supposedly useful for setting
         * cookie paths.
         * @return The "context path", whatever that is.
         */
        public String getContextPath() {
            return this.req.getContextPath();
        }
    }
    /**
     * Must behave like processResponse(Request,Response), but will be passed
     * (indirectly) certain lower-level info about the incoming HTTP request so that the
     * handler can access session-related information. The handler "should most definitely not" use
     * the HttpServletRequest for anything but:
     *
     * - Getting or setting session data.
     * - Getting or setting cookies.
     *
     * Any other operations are performed at one's own risk, and may interfere
     * with the overlying request dispatcher.
     *
     * Implementations which _require_ a HttpServletRequest/HttpServletResponse in order to function
     * should throw an exception from their processRequest(Response,Request) implementation if they do not
     * get passed one. Implementations which do not _require_ one could call this implementation from the
     * two-argument form, passing null as the hreq argument.
     *
     * Request dispatcher implementations "should" check the type of a loaded handler, and if
     * it is-a ServletResponseHandler then this overload of processResponse() should
     * be called instead of the two-argument form.
     *
     * @param sinfo Contains certain info about the inbound request.
     * @param req The inbound Request object, fully populated.
     * @param resp The out-bound Response object which should be populated by
     * the implementation.
     * @throws Exception Implementations may throw arbitrary exceptions.
     */
    public void processResponse(ServletInfo sinfo, Request req, Response resp) throws Exception;
}
